package com.atguigu.gulimall.order.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.atguigu.common.constant.OrderConstant;
import com.atguigu.common.exception.NoStockException;
import com.atguigu.common.to.HasStockTo;
import com.atguigu.common.to.mq.SeckillOrderTo;
import com.atguigu.common.utils.R;
import com.atguigu.common.vo.MemberVo;
import com.atguigu.gulimall.order.entity.OrderItemEntity;
import com.atguigu.gulimall.order.enume.OrderStatusEnum;
import com.atguigu.gulimall.order.feign.CartFeignService;
import com.atguigu.gulimall.order.feign.MemberFeignService;
import com.atguigu.gulimall.order.feign.ProductFeignService;
import com.atguigu.gulimall.order.feign.WareFeignService;
import com.atguigu.gulimall.order.interceptor.OrderWebIntereptor;
import com.atguigu.gulimall.order.service.OrderItemService;
import com.atguigu.gulimall.order.to.*;
import com.atguigu.gulimall.order.vo.*;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.Query;

import com.atguigu.gulimall.order.dao.OrderDao;
import com.atguigu.gulimall.order.entity.OrderEntity;
import com.atguigu.gulimall.order.service.OrderService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;


@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {
    public ThreadLocal<OrderSubmitVo> submitVoThreadLocal = new ThreadLocal<>();

    @Autowired
    private OrderItemService orderItemService;
    @Autowired
    MemberFeignService memberFeignService;

    @Autowired
    CartFeignService cartFeignService;
    @Autowired
    WareFeignService wareFeignService;
    @Autowired
    ProductFeignService productFeignService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    ThreadPoolExecutor executor;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public OrderConfirmVo toTrade() throws ExecutionException, InterruptedException {
        MemberVo memberVo = OrderWebIntereptor.loginUser.get();
        OrderConfirmVo confirmVo = new OrderConfirmVo();
        //获取当前线程下ThreadLocal里存的数据
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

        CompletableFuture<Void> addressTask = CompletableFuture.runAsync(() -> {
            //共享主线程的ThreadLocal
            RequestContextHolder.setRequestAttributes(requestAttributes);
            //获取用户的所有收货地址信息
            List<MemberAddressVo> addressVos = memberFeignService.currentUserAddresses(memberVo.getId());
            confirmVo.setMemberAddressVos(addressVos);
        }, executor);
        CompletableFuture<Void> cartTask = CompletableFuture.runAsync(() -> {
            //共享主线程的ThreadLocal
            RequestContextHolder.setRequestAttributes(requestAttributes);
            //获取购物车所选的购物项
            List<OrderItemVo> itemVos = cartFeignService.currentMemberCartitems(memberVo.getId());
            confirmVo.setItems(itemVos);
        }, executor).thenRunAsync(() -> {
            List<OrderItemVo> items = confirmVo.getItems();
            //调用库存服务查询库存所有sku库存信息
            List<Long> skuIds = items.stream().map(item -> item.getSkuId()).collect(Collectors.toList());
            R r = wareFeignService.getHasStock(skuIds);
            List<HasStockTo> stock = r.getData(new TypeReference<List<HasStockTo>>() {
            });
            Map<Long, Boolean> map = stock.stream().collect(Collectors.toMap(HasStockTo::getSkuId, HasStockTo::getStock));
            confirmVo.setStocks(map);
        }, executor);

        //获取会员积分信息
        Integer integration = memberVo.getIntegration();
        confirmVo.setIntegration(integration);
        //其他信息自动计算

        CompletableFuture.allOf(addressTask, cartTask).get();
        //TODO 防重令牌
        String token = UUID.randomUUID().toString().replace("-", "");
        //保存到页面
        confirmVo.setOrderToken(token);
        //保存到redis当中
        stringRedisTemplate.opsForValue().set(OrderConstant.ORDER_TOKEN_PREFIX + memberVo.getId(), token);
        return confirmVo;
    }

//    @GlobalTransactional 使用的at模式，底层加了很多锁，导致并发性低，不适合高并发场景
    @Transactional
    @Override
    public SubmitOrderResponseVo submitOrder(OrderSubmitVo orderSubmitVo) throws NoStockException{
        submitVoThreadLocal.set(orderSubmitVo);
        //下单，创建订单，验证令牌，验证价格，锁定库存
        SubmitOrderResponseVo responseVo = new SubmitOrderResponseVo();
        responseVo.setCode(0);
        MemberVo memberVo = OrderWebIntereptor.loginUser.get();
//        String redisToken = stringRedisTemplate.opsForValue().get(OrderConstant.ORDER_TOKEN_PREFIX + memberVo.getId());
        String orderToken = orderSubmitVo.getOrderToken();
        //使用lua脚本保证对比和删除令牌的原子性
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Long res = stringRedisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class),
                Arrays.asList(OrderConstant.ORDER_TOKEN_PREFIX + memberVo.getId()), orderToken);
        //验证令牌
        if (res == 1L) {
            //令牌验证成功
            //创建订单,验证价格，锁定库存
            //1.创建订单和订单项
            OrderCreateTo orderCreateTo = createOrderTo();
            //2.验价
            Double sub = orderCreateTo.getPayPrice().doubleValue()-orderSubmitVo.getPayPrice().doubleValue();
            if(sub<0.01){
                //验价成功
                //锁定库存
            }
            else {
                //验价失败
                responseVo.setCode(2);
                return responseVo;
            }
            //3.保存订单
            saveOrder(orderCreateTo);
            //4.锁定库存
            LockStockTo lockStockTo = new LockStockTo();
            lockStockTo.setOrderSn(orderCreateTo.getOrder().getOrderSn());
            List<OrderItemEntity> orderItems = orderCreateTo.getOrderItems();
            List<OrderItemVo> itemVoList = orderItems.stream().map(item -> {
                OrderItemVo orderItemVo = new OrderItemVo();
                orderItemVo.setSkuId(item.getSkuId());
                orderItemVo.setCount(item.getSkuQuantity());
                orderItemVo.setTitle(item.getSkuName());
                return orderItemVo;
            }).collect(Collectors.toList());
            lockStockTo.setOrderItems(itemVoList);

            R r = wareFeignService.lock(lockStockTo);
            if(r.getCode()==0){
                //锁定成功
                responseVo.setOrder(orderCreateTo.getOrder());
//                int i = 1/0;
                //下单完成发送消息到延时队列
                rabbitTemplate.convertAndSend("order-event-exhange","order.create.order",orderCreateTo.getOrder());
                return responseVo;
            }
            else {
                //锁定失败
                responseVo.setCode(3);
                throw new NoStockException("锁定库存失败");
            }
        } else {
            //验证失败
            responseVo.setCode(1);
            return responseVo;
        }
    }

    @Override
    public OrderEntity orderStatus(String orderSn) {
        OrderEntity orderEntity = this.baseMapper.selectOne(new QueryWrapper<OrderEntity>().eq("order_sn", orderSn));
        return orderEntity;
    }

    @Override
    public OrderEntity listWithItems(String orderSn) {
        OrderEntity order = this.getOne(new QueryWrapper<OrderEntity>().eq("order_sn", orderSn));

        List<OrderItemEntity> orderItemEntities = orderItemService.listByOrderSn(orderSn);

        order.setItem(orderItemEntities);
        return order;
    }

    /**
     * 查询当前用户所有订单以及订单项
     *
     * @return
     */
    @Override
    public List<OrderEntity> memberOrders() {
        MemberVo memberVo = OrderWebIntereptor.loginUser.get();
        List<OrderEntity> orderEntities = this.list(new QueryWrapper<OrderEntity>().eq("member_id", memberVo.getId()));
        List<OrderEntity> collect = orderEntities.stream().map(item -> {
            OrderEntity orderEntity = this.listWithItems(item.getOrderSn());
            item.setItem(orderEntity.getItem());
            return item;
        }).collect(Collectors.toList());
        return collect;
    }

    /**
     * 保存秒杀订单信息
     * @param seckillOrderTo
     */
    @Override
    public void createSeckillOrder(SeckillOrderTo seckillOrderTo) {
        //TODO  保存秒杀订单号信息
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
        orderEntity.setOrderSn(seckillOrderTo.getOrderSn());
        orderEntity.setMemberId(seckillOrderTo.getMemberId());
        BigDecimal payAmount = seckillOrderTo.getSeckillPrice().multiply(new BigDecimal(seckillOrderTo.getNum() + ""));
        orderEntity.setPayAmount(payAmount);
        this.save(orderEntity);
        //保存订单项信息
        OrderItemEntity orderItemEntity = new OrderItemEntity();
        orderItemEntity.setOrderSn(orderEntity.getOrderSn());
        orderItemEntity.setRealAmount(payAmount);
        orderItemEntity.setSkuQuantity(seckillOrderTo.getNum());
        orderItemService.save(orderItemEntity);
    }


    /**
     * 保存订单信息
     * @param orderCreateTo
     */
    private void saveOrder(OrderCreateTo orderCreateTo) {
        OrderEntity order = orderCreateTo.getOrder();
        order.setModifyTime(new Date());
        //保单订单
        this.save(order);
        //保存订单项数据
        List<OrderItemEntity> orderItems = orderCreateTo.getOrderItems();
        orderItemService.saveBatch(orderItems);

    }

    /**
     * 封装订单和订单项数据
     * @return
     */
    private OrderCreateTo createOrderTo() {
        OrderCreateTo orderCreateTo = new OrderCreateTo();
        //创建订单
        OrderEntity orderEntity = createOrder();
        //创建所有订单项
        List<OrderItemEntity> orderItemEntities = createOrderItems(orderEntity.getOrderSn());
       //计算各种价格总额
        orderEntity = computePrice(orderEntity,orderItemEntities);

        orderCreateTo.setOrder(orderEntity);
        orderCreateTo.setOrderItems(orderItemEntities);
        orderCreateTo.setPayPrice(orderEntity.getPayAmount());
        orderCreateTo.setFare(orderEntity.getFreightAmount());
        return orderCreateTo;
    }

    /**
     * 计算各种总额
     * @param orderEntity
     * @param orderItemEntities
     * @return
     */
    private OrderEntity computePrice(OrderEntity orderEntity,List<OrderItemEntity> orderItemEntities) {
        BigDecimal amount = new BigDecimal("0.0");
        BigDecimal prot = new BigDecimal("0.0");
        Integer ingr = new Integer(0);
        Integer growth = new Integer("0");
        for (OrderItemEntity item : orderItemEntities) {
            amount = item.getRealAmount().add(amount);
            prot = item.getPromotionAmount().add(prot);
            growth = item.getGiftGrowth()+growth;
            ingr = item.getGiftIntegration()+ingr;
        }
        orderEntity.setTotalAmount(amount);
        orderEntity.setPromotionAmount(prot);
        orderEntity.setGrowth(growth);
        orderEntity.setIntegrationAmount(new BigDecimal(ingr.toString()));
        orderEntity.setPayAmount(amount);
        return orderEntity;
    }

    /**
     * 创建所有订单项
     *
     * @return
     */
    private List<OrderItemEntity> createOrderItems(String orderSn) {
        MemberVo memberVo = OrderWebIntereptor.loginUser.get();
        //获取当前购物车的商品信息
        List<OrderItemVo> orderItemVos = cartFeignService.currentMemberCartitems(memberVo.getId());
        List<OrderItemEntity> itemEntities = null;
        if (orderItemVos != null && orderItemVos.size() > 0) {
            //封装订单项
            itemEntities = orderItemVos.stream().map(cartItem -> {
                OrderItemEntity itemEntity = createOrderItem(cartItem);
                itemEntity.setOrderSn(orderSn);
                return itemEntity;
            }).collect(Collectors.toList());
        }
        return itemEntities;
    }

    /**
     * 创建某个订单项
     *
     * @param cartItem
     * @return
     */
    private OrderItemEntity createOrderItem(OrderItemVo cartItem) {
        OrderItemEntity orderItemEntity = new OrderItemEntity();
        //封装sku信息
        orderItemEntity.setSkuId(cartItem.getSkuId());
        orderItemEntity.setSkuName(cartItem.getTitle());
        orderItemEntity.setSkuPic(cartItem.getImage());
        orderItemEntity.setSkuPrice(cartItem.getPrice());
        orderItemEntity.setSkuQuantity(cartItem.getCount());
        List<String> skuAttrValues = cartItem.getSkuAttrValues();
        String attrValues = StringUtils.collectionToDelimitedString(skuAttrValues, ";");
        orderItemEntity.setSkuAttrsVals(attrValues);
        //封装spu信息
        R r = productFeignService.spuinfoBySkuId(cartItem.getSkuId());
        SpuInfoTo data = r.getData(new TypeReference<SpuInfoTo>() {
        });
        orderItemEntity.setSpuBrand(data.getBrandId().toString());
        orderItemEntity.setSpuId(data.getId());
        orderItemEntity.setSpuName(data.getSpuName());
        orderItemEntity.setCategoryId(data.getCatalogId());

        //封装优惠信息...
        //封装积分信息
        orderItemEntity.setGiftGrowth(cartItem.getPrice().intValue());
        orderItemEntity.setGiftIntegration(cartItem.getPrice().intValue());

        //封装价格信息
        orderItemEntity.setRealAmount(cartItem.getPrice().multiply(new BigDecimal(cartItem.getCount())));
        orderItemEntity.setGiftGrowth(cartItem.getPrice().multiply(new BigDecimal(cartItem.getCount())).intValue());
        orderItemEntity.setPromotionAmount(cartItem.getPrice().multiply(new BigDecimal(cartItem.getCount())));
        return orderItemEntity;
    }

    /**
     * 创建订单
     *
     * @return
     */
    private OrderEntity createOrder() {
        //获取前端提交数据
        OrderSubmitVo orderSubmitVo = submitVoThreadLocal.get();
        MemberVo memberVo = OrderWebIntereptor.loginUser.get();
        OrderEntity orderEntity = new OrderEntity();
        //会员id
        orderEntity.setMemberId(memberVo.getId());
        String orderId = IdWorker.getTimeId();//根据时间随机生成id
        orderEntity.setOrderSn(orderId);
        R r = wareFeignService.fare(orderSubmitVo.getAddrId());
        FareTo fare = r.getData(new TypeReference<FareTo>() {
        });
        //设置运费
        orderEntity.setFreightAmount(fare.getFare());
        //设置收货人信息
        orderEntity.setReceiverName(fare.getAddress().getName());
        orderEntity.setReceiverPhone(fare.getAddress().getPhone());
        orderEntity.setReceiverCity(fare.getAddress().getCity());
        orderEntity.setReceiverDetailAddress(fare.getAddress().getDetailAddress());
        orderEntity.setReceiverPostCode(fare.getAddress().getPostCode());
        orderEntity.setReceiverProvince(fare.getAddress().getProvince());
        orderEntity.setReceiverRegion(fare.getAddress().getRegion());
        //设置状态信息
        orderEntity.setDeleteStatus(0);
        orderEntity.setConfirmStatus(0);
        orderEntity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
        return orderEntity;
    }

}